﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SlimDX;
using SlimDX.Direct3D9;

namespace Gype.UI.D3D9
{
    internal class RectangleProvider
    {
        public RectangleProvider(Rendertarget9 target, Device dev)
        {
            mDevice = dev;
            mTarget = target;
            mVertexShader = new ShaderCompiler<VertexShader>(dev, Shaders.DrawRectangle, "VertexMain", "vs_3_0");
            mPixelShader = new ShaderCompiler<PixelShader>(dev, Shaders.DrawRectangle, "PixelMain", "ps_3_0");
            mPixelShaderFill = new ShaderCompiler<PixelShader>(dev, Shaders.DrawRectangle, "PixelMainFill", "ps_3_0");
            
            mDescSize = mPixelShader.ConstantTable["elementSize"];
            mDescStroke = mPixelShader.ConstantTable["strokeWidth"];
            mDescMatrix = mVertexShader.ConstantTable["orthoProjMatrix"];
            mBrushParam = mPixelShaderFill.ConstantTable["brushSampler"];
            mViewportParam = mVertexShader.ConstantTable["viewportSize"];
            mTransformParam = mVertexShader.ConstantTable["transformMatrix"];
            mMaskParam = mPixelShader.ConstantTable["fillMask"];
        }

        public void DrawToTarget(float stroke, Vector2 position, Vector2 size, Brush brush, RectangleFillMask mask)
        {
            Vector4 maskVector = new Vector4((mask & RectangleFillMask.Left) != 0 ? 1 : -1, (mask & RectangleFillMask.Top) != 0 ? 1 : -1,
                (mask & RectangleFillMask.Right) != 0 ? 1 : -1, (mask & RectangleFillMask.Bottom) != 0? 1 : -1);

            brush.ApplyToShader(mPixelShaderFill, mBrushParam);
            var vertices = mTarget.CreateTriangleFan(position, size, new Color4(1, 1, 1, 1));
            mDevice.VertexShader = mVertexShader.Shader;
            mDevice.PixelShader = mPixelShader.Shader;

            mVertexShader.SetValue(mDescMatrix, mTarget.OrthoMatrix);
            mVertexShader.SetValue(mTransformParam, mTarget.Transform);
            mVertexShader.SetValue(mViewportParam, mTarget.Viewport);
            mPixelShader.SetValue(mDescStroke, stroke);
            mPixelShader.SetValue(mDescSize, size);
            mPixelShader.SetValue(mMaskParam, maskVector);

            mDevice.VertexDeclaration = mTarget.UIVertexDeclaration;
            mDevice.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vertices);

            mDevice.VertexShader = null;
            mDevice.PixelShader = null;
        }

        public void Fill(Vector2 position, Vector2 size, Brush brush)
        {
            brush.ApplyToShader(mPixelShaderFill, mBrushParam);
            var vertices = mTarget.CreateTriangleList(position, size, new Color4(1, 1, 1, 1));
            mDevice.VertexShader = mVertexShader.Shader;
            mDevice.PixelShader = mPixelShaderFill.Shader;

            mVertexShader.SetValue(mDescMatrix, mTarget.OrthoMatrix);
            mVertexShader.SetValue(mTransformParam, mTarget.Transform);
            mVertexShader.SetValue(mViewportParam, mTarget.Viewport);

            mDevice.VertexDeclaration = mTarget.UIVertexDeclaration;
            mDevice.DrawUserPrimitives(PrimitiveType.TriangleList, 2, vertices);

            mDevice.VertexShader = null;
            mDevice.PixelShader = null;
        }

        Device mDevice;
        Rendertarget9 mTarget;
        ConstantDescription mDescStroke;
        ConstantDescription mDescSize;
        ConstantDescription mDescMatrix;
        ConstantDescription mBrushParam;
        ConstantDescription mViewportParam;
        ConstantDescription mTransformParam;
        ConstantDescription mMaskParam;
        ShaderCompiler<VertexShader> mVertexShader;
        ShaderCompiler<PixelShader> mPixelShader;
        ShaderCompiler<PixelShader> mPixelShaderFill;
    }
}
